﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;

namespace Useful.GUI.HierarchyDataGridView
{
    public class HierarchyDataGridView : GroupingDataGridView
    {
        // Создание списка строк для группы
        private static List<DataGridViewRow> CreateRowGroup()
        {
            List<DataGridViewRow> group = new List<DataGridViewRow>();

            return group;
        }

        public override void ClearGroupRow()
        {
            foreach (DataGridViewRow row in Rows)
            {
                if (row.HeaderCell is RowHeaderCell)
                {
                    ((RowHeaderCell)row.HeaderCell).ClearGroups();
                }
            }

            foreach (DataGridViewRow row in Rows)
            {
                row.Visible = true;
            }
        }

        // Группировка по колонке
        public override void GroupRows(string columnName)
        {
            GroupRows(columnName, true);
        }

        public void GroupRows(string columnName, int beginRowIndex)
        {
            GroupRows(columnName, true, beginRowIndex);
        }

        public void UnGroupRows()
        {
            ClearGroupRow();
        }

        // Группировка по колонке
        public void GroupRows(string columnName, bool clear, int beginRowIndex)
        {
            if(clear)
                this.ClearGroupRow();

            List<string> colNames = new List<string>();
            colNames.Add(columnName);

            GroupRows(colNames, 0, this.Rows, beginRowIndex);
        }

        public void GroupRows(string columnName, bool clear)
        {
            GroupRows(columnName, clear, 0);
        }

        public void GroupRows(List<string> columnNames)
        {
            GroupRows(columnNames, 0, this.Rows, 0);
        }

        public void GroupRows(List<string> columnNames, int colIndex, IEnumerable rows, int beginRowIndex)
        {
            if (colIndex < columnNames.Count)
            {
                string columnName = columnNames[colIndex];

                string gName = null;
                List<DataGridViewRow> group = null;

                GroupItem groupItem = null;

                foreach (DataGridViewRow row in rows)
                {
                    if (row.Index < beginRowIndex)
                        continue;

                    if ((row.Cells[columnName].Value ?? String.Empty).ToString() != gName)
                    {
                        if (group != null)
                        {
                            RowHeaderCell.SetLastGroupHeaderCell(group[group.Count - 1].HeaderCell, group.Count > 1);

                            GroupRows(columnNames, colIndex + 1, group, beginRowIndex);
                        }

                        gName = (row.Cells[columnName].Value ?? String.Empty).ToString();
                        group = CreateRowGroup();

                        if (this.DataSource != null)
                            row.HeaderCell = RowHeaderCell.AddGroupHeaderCell(row.HeaderCell, group, grid_RowBeforeCollapsing, out groupItem);
                        else
                            row.HeaderCell = RowHeaderCell.AddGroupHeaderCell(group);
                    }
                    else
                        row.HeaderCell = RowHeaderCell.AddGroupItemCell(row.HeaderCell, groupItem);

                    group.Add(row);
                }

                if (group != null)
                {
                    RowHeaderCell.SetLastGroupHeaderCell(group[group.Count - 1].HeaderCell, group.Count > 1);

                    GroupRows(columnNames, colIndex + 1, group, beginRowIndex);
                }
            }
        }

        //TODO
        private void grid_RowBeforeCollapsing(object sender, RowHeaderCell.CollapsingEventArgs e)
        {
            GoToFirstRowInGroup(e);
        }

        //TODO
        private void GoToFirstRowInGroup(RowHeaderCell.CollapsingEventArgs e)
        {
            try
            {
                if (CurrentCell != null)
                {
                    int rowIndex = e.HeaderCell.Groups[e.GroupIndex].GetRow(0).Index;
                    int colIndex = CurrentCell.ColumnIndex;

                    CurrentCell = this[colIndex, rowIndex];
                }
            }
            catch (Exception ex)
            {
                MessageBoxHelper.ShowError("GoToFirstRowInGroup: " + ex.Message);
            }
        }

        protected override void SetSelectedCellCore(int columnIndex, int rowIndex, bool selected)
        {
            if (columnIndex >= 0 && rowIndex >= 0)
            {
                if (this[columnIndex, rowIndex] is DataGridViewStretchHelperTextBoxCell)
                {
                    DataGridViewStretchHelperTextBoxCell c = (DataGridViewStretchHelperTextBoxCell)this[columnIndex, rowIndex];

                    base.SetSelectedCellCore(c.BaseCell.ColumnIndex, c.BaseCell.RowIndex, selected);
                }
                else
                    base.SetSelectedCellCore(columnIndex, rowIndex, selected);
            }
            else
                base.SetSelectedCellCore(columnIndex, rowIndex, selected);

            Invalidate();
        }

        protected override bool SetCurrentCellAddressCore(int columnIndex, int rowIndex, bool setAnchorCellAddress, bool validateCurrentCell, bool throughMouseClick)
        {
            if (columnIndex >= 0 && rowIndex >= 0)
            {
                if (this[columnIndex, rowIndex] is DataGridViewStretchHelperTextBoxCell)
                {
                    DataGridViewStretchHelperTextBoxCell c = (DataGridViewStretchHelperTextBoxCell)this[columnIndex, rowIndex];

                    return base.SetCurrentCellAddressCore(c.BaseCell.ColumnIndex, c.BaseCell.RowIndex, setAnchorCellAddress, validateCurrentCell, throughMouseClick);
                }
                else
                    return base.SetCurrentCellAddressCore(columnIndex, rowIndex, setAnchorCellAddress, validateCurrentCell, throughMouseClick);
            }
            else
                return base.SetCurrentCellAddressCore(columnIndex, rowIndex, setAnchorCellAddress, validateCurrentCell, throughMouseClick);
        }

        protected override void OnCellDoubleClick(DataGridViewCellEventArgs e)
        {
            if (e.ColumnIndex >= 0 && e.RowIndex >= 0)
            {                
                if (this[e.ColumnIndex, e.RowIndex] is DataGridViewStretchHelperTextBoxCell)
                {
                    DataGridViewStretchHelperTextBoxCell c = (DataGridViewStretchHelperTextBoxCell)this[e.ColumnIndex, e.RowIndex];

                    BeginEdit(true);

                    base.OnCellDoubleClick(new DataGridViewCellEventArgs(c.BaseCell.ColumnIndex, c.BaseCell.RowIndex));
                }
                else if (this[e.ColumnIndex, e.RowIndex] is DataGridViewStretchTextBoxCell)
                {
                    BeginEdit(true);
                }
                else
                {
                    CallProcessCellDoubleClick(e);

                    //base.OnCellDoubleClick(e);
                }
            }
            else
                base.OnCellDoubleClick(e);
        }

        protected override void OnCellMouseDown(DataGridViewCellMouseEventArgs e)
        {
            if (e.RowIndex == -1 && e.ColumnIndex != -1 &&
                (Columns[e.ColumnIndex].HeaderCell is DataGridViewColumn2LevelHelperHeaderCell
                || Columns[e.ColumnIndex].HeaderCell is DataGridViewColumn2LevelHeaderCell)
                )
            {
                HitTestInfo hti = this.HitTest(e.X, e.Y);

                Rectangle rect1 = GetCellDisplayRectangle(hti.ColumnIndex, hti.RowIndex, false);
                Rectangle rect = new Rectangle(rect1.X, rect1.Y + rect1.Height / 2, rect1.Width, rect1.Height / 2);

                if (rect.Contains(e.Location))
                    base.OnCellMouseDown(e);
            }
            else
                base.OnCellMouseDown(e);
        }

        protected override void OnMouseClick(MouseEventArgs e)
        {
            if (CurrentCell != null)
                InvalidateCell(CurrentCell);

            HitTestInfo hti = this.HitTest(e.X, e.Y);

            if (hti.RowIndex == -1 && hti.ColumnIndex != -1 &&
                (Columns[hti.ColumnIndex].HeaderCell is DataGridViewColumn2LevelHelperHeaderCell
                || Columns[hti.ColumnIndex].HeaderCell is DataGridViewColumn2LevelHeaderCell)
                )
            {
                if (Columns[hti.ColumnIndex].HeaderCell is DataGridViewColumn2LevelHelperHeaderCell)
                {
                    DataGridViewColumn2LevelHelperHeaderCell c = (DataGridViewColumn2LevelHelperHeaderCell)Columns[hti.ColumnIndex].HeaderCell;

                    Rectangle rect1 = GetCellDisplayRectangle(hti.ColumnIndex, hti.RowIndex, false);
                    Rectangle rect = new Rectangle(rect1.X, rect1.Y + rect1.Height / 2, rect1.Width, rect1.Height / 2);

                    if (rect.Contains(e.Location))
                    {
                        if (c.IsMouseInCell(e.Location))
                            base.OnMouseClick(e);
                        else
                        {
                            c.ProcessCheck();
                            this.InvalidateCell(c);
                        }
                    }
                }
                else
                {
                    DataGridViewColumn2LevelHeaderCell c = (DataGridViewColumn2LevelHeaderCell)Columns[hti.ColumnIndex].HeaderCell;

                    Rectangle rect1 = GetCellDisplayRectangle(hti.ColumnIndex, hti.RowIndex, false);
                    Rectangle rect = new Rectangle(rect1.X, rect1.Y + rect1.Height / 2, rect1.Width, rect1.Height / 2);

                    if (rect.Contains(e.Location))
                    {
                        if (c.IsMouseInCell(e.Location))
                            base.OnMouseClick(e);
                        else
                        {
                            c.ProcessCheck();
                            this.InvalidateCell(c);
                        }
                    }
                }
            }
            else if (hti.RowIndex == -1 && hti.ColumnIndex != -1 && Columns[hti.ColumnIndex].HeaderCell is DataGridViewColumnCheckedHeaderCell)
            {
                DataGridViewColumnCheckedHeaderCell c = (DataGridViewColumnCheckedHeaderCell)Columns[hti.ColumnIndex].HeaderCell;

                if (c.IsMouseInCell(e.Location))
                    base.OnMouseClick(e);
                else
                {
                    c.ProcessCheck();
                    this.InvalidateCell(c);
                }
            }
            else
                base.OnMouseClick(e);
        }

        protected override void OnMouseMove(MouseEventArgs e)
        {
            HitTestInfo hti = this.HitTest(e.X, e.Y);

            if (hti.RowIndex == -1 && hti.ColumnIndex != -1 &&
                (Columns[hti.ColumnIndex].HeaderCell is DataGridViewColumn2LevelHelperHeaderCell
                || Columns[hti.ColumnIndex].HeaderCell is DataGridViewColumn2LevelHeaderCell)
                )
            {
                Rectangle rect1 = GetCellDisplayRectangle(hti.ColumnIndex, hti.RowIndex, false);
                Rectangle rect = new Rectangle(rect1.X, rect1.Y + rect1.Height / 2, rect1.Width, rect1.Height / 2);

                if (rect.Contains(e.Location))
                    base.OnMouseMove(e);
                else
                {
                    if (this.Cursor == Cursors.SizeWE)
                        this.Cursor = Cursors.Arrow;
                }
            }
            else
                base.OnMouseMove(e);
        }

        protected override void OnKeyDown(KeyEventArgs e)
        {
            if (e.KeyCode == Keys.F2)
                BeginEdit(false);

            base.OnKeyDown(e);
        }

        protected override void OnColumnWidthChanged(DataGridViewColumnEventArgs e)
        {
            Invalidate();

            base.OnColumnWidthChanged(e);
        }


        protected override void OnCellMouseClick(DataGridViewCellMouseEventArgs e)
        {
            if ((ShowContextMenu != null) && e.Button == MouseButtons.Right && e.RowIndex != -1 && e.ColumnIndex != -1)
            {
                Rectangle rect = this.GetCellDisplayRectangle(e.ColumnIndex, e.RowIndex, true);
                ShowContextMenu.Show(this, rect.X + e.X, rect.Y + e.Y);
            }

            base.OnCellMouseClick(e);
        }

        public override void CleaAll()
        {
            base.Rows.Clear();

            Columns.Clear();
        }

        protected override void OnCellMouseEnter(DataGridViewCellEventArgs e)
        {
            base.OnCellMouseEnter(e);

            if (e.ColumnIndex != -1 && e.RowIndex != -1)
            {
                int columnIndex = e.ColumnIndex;

                if (this[e.ColumnIndex, e.RowIndex] is DataGridViewStretchHelperTextBoxCell)
                {
                    columnIndex = ((DataGridViewStretchHelperTextBoxCell)this[e.ColumnIndex, e.RowIndex]).BaseCell.ColumnIndex;
                }

                ToolTipTextNeededEventArgs ea = new ToolTipTextNeededEventArgs(columnIndex, e.RowIndex);

                CallProcessCellToolTipTextNeeded2(ea);

                if (!String.IsNullOrEmpty(ea.ToolTipText))
                {
                    CallActivateToolTip(ea.ToolTipText, columnIndex, e.RowIndex);
                }
            }
        }


        public void CollapseFirstGroup(bool visible)
        {
            CurrentCell = null;

            foreach (DataGridViewRow row in Rows)
            {
                if (row.HeaderCell is RowHeaderCell)
                {
                    RowHeaderCell rhc = (RowHeaderCell)row.HeaderCell;

                    rhc.Collapse(0, row.Visible && visible);
                }
            }
        }
    }
}